package com.elite.groovy.kh;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @projectName: ngsapitask-cdcs
 * @package: com.elite.groovy.kh
 * @className: Test
 * @author: LiJT
 * @description: TODO
 * @date: 2023-05-05 20:17
 * @version: 1.0
 */
public class CosFileUtils {
    private static final Log log = LogFactory.getLog(CosFileUtils.class);

    /**
     * @param secretId:SecretId
     * @param secretKey:SecretKey
     * @param Region:Bucket的地域
     * @param inBucketName:存储桶名称
     * @param cosFilePath:对象键(Key)是对象在存储桶中的唯一标识
     * @param localFile:本地文件路径
     * @return void
     * @author LiJT
     * @description TODO
     * @date 2023-06-21 14:06
     */
    public static boolean download(String secretId, String secretKey, String Region, String inBucketName, String cosFilePath, String localFile) {

        log.debug("CosFileUtils download Region:" + Region + " inBucketName:" + inBucketName + " cosFilePath:" + cosFilePath + " localFile:" + localFile);

        boolean downloadFlag = true;
        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        TransferManager transferManager = createTransferManager(secretId, secretKey, Region);
        File downloadFile = new File(localFile);

        GetObjectRequest getObjectRequest = new GetObjectRequest(inBucketName, cosFilePath);

        try {
            // 返回一个异步结果 download, 可同步的调用 waitForUploadResult 等待 download 结束.
            Download download = transferManager.download(getObjectRequest, downloadFile);

            // 可以选择查看下载进度
            showTransferProgress(download);

            // 或者阻塞等待完成
            download.waitForCompletion();

            log.debug("download directory done.");
        } catch (CosServiceException e) {
            downloadFlag = false;
            e.printStackTrace();
        } catch (CosClientException e) {
            downloadFlag = false;
            e.printStackTrace();
        } catch (InterruptedException e) {
            downloadFlag = false;
            e.printStackTrace();
        }

        // 确定本进程不再使用 transferManager 实例之后，关闭即可
        shutdownTransferManager(transferManager);

        return downloadFlag;

    }

    // 创建 TransferManager
    // 使用高级接口的操作之前，必须先创建一个 TransferManager 的实例。
    static TransferManager createTransferManager(String inSecretId, String inSecretKey, String inRegion) {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        COSClient cosClient = createCOSClient(inSecretId, inSecretKey, inRegion);

        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);

        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);

        return transferManager;
    }


    // 创建 COSClient
    // 调用 COS 的接口之前，必须先创建一个 COSClient 的实例。
    static COSClient createCOSClient(String inSecretId, String inSecretKey, String inRegion) {
        // 设置用户身份信息。
        String secretId = inSecretId;
        String secretKey = inSecretKey;

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);

        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        clientConfig.setRegion(new Region(inRegion));

        // 设置请求协议, http 或者 https
        clientConfig.setHttpProtocol(HttpProtocol.https);

        // 以下的设置，是可选的
        // 设置 socket 读取超时，默认 30s
        clientConfig.setSocketTimeout(30 * 1000);
        // 设置建立连接超时，默认 30s
        clientConfig.setConnectionTimeout(30 * 1000);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }

    // 显示下载进度
    // 要显示下载进度首先需要一个自己的打印下载进度的函数，在这个函数里通过调用接口来获取已经成功下载的大小从而计算出当前进度。
    static void showTransferProgress(Transfer transfer) {
        log.debug(transfer.getDescription());

        // transfer.isDone() 查询下载是否已经完成
        while (!transfer.isDone()) {
            try {
                // 每 2 秒获取一次进度
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                return;
            }

            TransferProgress progress = transfer.getProgress();
            long sofar = progress.getBytesTransferred();
            long total = progress.getTotalBytesToTransfer();
            double pct = progress.getPercentTransferred();
            log.debug("upload progress: [" + sofar + " / " + total + "] = " + pct + "%");
        }

        // 完成了 Completed，或者失败了 Failed
        log.debug(transfer.getState());
    }

    // 关闭 TransferManager
    // 在确定不再通过 TransferManager 的实例调用高级接口之后，一定要关闭这个实例，防止资源泄露。
    static void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(true);
    }
}
